home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 February / EnigmA AMIGA RUN 04 (1996)(G.R. Edizioni)(IT)[!][issue 1996-02][Skylink CD III].iso / earcd / comm2 / sanautil.lha / sanautil.c < prev    next >
C/C++ Source or Header  |  1995-08-04  |  26KB  |  1,105 lines

  1. /*
  2.  * a simple SANA2 utility program
  3.  *
  4.  * Timo Rossi <trossi@jyu.fi>, 1992-1995
  5.  *
  6.  *  Copyright © 1992-1995 by Timo Rossi.
  7.  *  freely distributed for non-commercial purposes.
  8.  */
  9.  
  10. /*
  11.  * Version 0.38 -- 4.8.95
  12.  *  - now DUMP/RECEIVE work with all device types
  13.  *  - document file created.
  14.  *
  15.  * Version 0.37 -- 18.07.94
  16.  *  - added RECEIVE
  17.  *
  18.  * Version 0.36 -- 14.02.94
  19.  *
  20.  * Version 0.34
  21.  *  - DATA-keyword allows sending of ASCII strings
  22.  *  - reads device & unit from env. vars SANA2.Device & SANA2.Unit
  23.  *  - multicast packet length & type setting fixed
  24.  *  - dump length fixed
  25.  *
  26.  */
  27.  
  28. #include <exec/types.h>
  29. #include <exec/errors.h>
  30. #include <exec/memory.h>
  31. #include <exec/devices.h>
  32. #include <dos/dos.h>
  33. #include <dos/rdargs.h>
  34.  
  35. #include <clib/exec_protos.h>
  36. #include <clib/dos_protos.h>
  37. #include <clib/alib_protos.h>
  38.  
  39. #include <stdlib.h>
  40. #include <string.h>
  41.  
  42. #ifdef __SASC
  43. #include <pragmas/exec_sysbase_pragmas.h>
  44. #include <pragmas/dos_pragmas.h>
  45. extern struct ExecBase *SysBase;
  46. extern struct DosLibrary *DOSBase;
  47. #define exit XCEXIT
  48. void MemCleanup(void) {}
  49. #define ALIGNED __aligned
  50. #endif
  51.  
  52. #include <devices/sana2.h>
  53.  
  54. #define VERSION "0"
  55. #define REVISION "38"
  56. #define DATE "4.8.95"
  57.  
  58. #define DEFAULT_DEVICE_NAME "a2065.device"
  59. #define DEFAULT_UNIT_NUMBER 0
  60.  
  61. #define DEFAULT_PACKET_TYPE 5000
  62. #define DEFAULT_PACKET_LEN 100
  63.  
  64. #define MAX_SPECIALSTATS 10
  65.  
  66. struct SpecialStatData {
  67.   struct Sana2SpecialStatHeader hdr;
  68.   struct Sana2SpecialStatRecord stat[MAX_SPECIALSTATS];
  69. };
  70.  
  71. char ProgName[] = "SANAutil";
  72.  
  73. static const char VersionString[] =
  74.    "$VER: SANAutil " VERSION "." REVISION " (" DATE ")";
  75.  
  76. char Prog_Template[] =
  77.     "-D=DEVICE/K,-U=UNIT/N/K,-A=ADDRESS/K,"
  78.     "-E=EXCLUSIVE/S,-P=PROMISCUOUS/S,"
  79.     "SEND/K,TYPE/N/K,LENGTH/N/K,DATA/K,REC=RECEIVE/K/N,"
  80.     "BROADCAST/S,DUMP/S,STATUS/S,CONFIG/S,ONLINE/S,OFFLINE/S,"
  81.     "MULTICAST/K,ADDMULTICAST/K,DELMULTICAST/K,"
  82.     "TRACKTYPE/N/K,UNTRACKTYPE/N/K,TYPESTAT/N/K";
  83.  
  84. enum Prog_Args {
  85.   DEVICE_ARG,
  86.   UNIT_ARG,
  87.   ADDR_ARG,
  88.   EXCL_ARG,
  89.   PROM_ARG,
  90.   SEND_ARG,
  91.   TYPE_ARG,
  92.   LENGTH_ARG,
  93.   DATA_ARG,
  94.   RECEIVE_ARG,
  95.   BROADCAST_ARG,
  96.   DUMP_ARG,
  97.   STATUS_ARG,
  98.   CONFIG_ARG,
  99.   ONLINE_ARG,
  100.   OFFLINE_ARG,
  101.   MULTICAST_ARG,
  102.   ADDMULTICAST_ARG,
  103.   DELMULTICAST_ARG,
  104.   TRACKTYPE_ARG,
  105.   UNTRACKTYPE_ARG,
  106.   TYPESTAT_ARG,
  107.   NUM_ARGS
  108. };
  109.  
  110. struct RDArgs *ProgArgs = NULL;
  111.  
  112. struct MsgPort *SanaPort = NULL;
  113. struct IOSana2Req *SanaReq = NULL;
  114. struct Device *SanaDev = NULL;
  115. UBYTE *PacketBuf = NULL;
  116. long PacketBufSize;
  117.  
  118. /*********/
  119.  
  120. #ifdef __SASC
  121. int __asm __saveds MemCopy(register __a0 UBYTE *to,
  122.                register __a1 UBYTE *from,
  123.                register __d0 LONG len)
  124. {
  125.   CopyMem(from, to, len);
  126.   return 1;
  127. }
  128. #else
  129. #error This can currently only be compiled with SAS/C 6.x
  130. #endif
  131.  
  132. /*
  133.  * Hex dump
  134.  *
  135.  */
  136. void HexDump(UBYTE *buf, LONG length)
  137. {
  138.    LONG l2, offset = 0;
  139.    int i;
  140.  
  141.    while(length)
  142.      {
  143.        l2 = length;
  144.        if(l2 > 16) l2 = 16;
  145.        /* hexdump buffer */
  146.        Printf("%06lx:", offset);
  147.        for(i = 0; i < l2; i++) Printf(" %02lx", buf[i]);
  148.        PutStr("\n");
  149.        /* --- */
  150.        buf += l2;
  151.        length -= l2;
  152.        offset += l2;
  153.      }
  154. }
  155.  
  156. /*
  157.  * Display an address (length in bytes as argument)
  158.  *
  159.  */
  160. void ShowAddress(UBYTE *addr, int len)
  161. {
  162.   len--;
  163.   while(len--)
  164.     Printf("%02lx:", *addr++);
  165.   Printf("%02lx", *addr);
  166. }
  167.  
  168. /*
  169.  * Parse an address and store it to *adr, return TRUE if successfull,
  170.  * FALSE if not.
  171.  *
  172.  */
  173. int ParseAddr(char *str, UBYTE *adr)
  174. {
  175.   int i, k, n;
  176.  
  177.   memset(adr, 0, SANA2_MAX_ADDR_BYTES); /* clear address */
  178.  
  179.   for(i=0; i<SANA2_MAX_ADDR_BYTES; i++)
  180.     {
  181.       if((k = stch_i(str, &n)) == 0)
  182.     return FALSE;
  183.       *adr++ = n;
  184.       str += k;
  185.       if(*str == '\0')
  186.     break;
  187.       if(i < SANA2_MAX_ADDR_BYTES-1 && *str++ != ':')
  188.     return FALSE;
  189.     }
  190.   return TRUE;
  191. }
  192.  
  193. /*
  194.  * fill a data buffer with the contents of a string
  195.  *
  196.  */
  197. void StringFill(char *addr, int len, char *str)
  198. {
  199.   char *s = str;
  200.  
  201.   while(len--)
  202.     {
  203.       *addr++ = *s++;
  204.       if(!*s) s = str;
  205.     }
  206. }
  207.  
  208. /*********/
  209.  
  210. /*
  211.  * Display error message
  212.  *
  213.  */
  214. void Sana2ErrorMsg(struct IOSana2Req *req)
  215. {
  216.   PutStr(" -- Error: ");
  217.   switch(req->ios2_Req.io_Error)
  218.     {
  219.       case IOERR_OPENFAIL:
  220.     PutStr("Device open failure");
  221.     break;
  222.  
  223.       case IOERR_ABORTED:
  224.     PutStr("IO Request aborted");
  225.     break;
  226.  
  227.       case IOERR_NOCMD:
  228.     PutStr("Command not supported");
  229.     break;
  230.  
  231.       case IOERR_BADLENGTH:
  232.     PutStr("Not a valid length");
  233.     break;
  234.  
  235.       case IOERR_BADADDRESS:
  236.     PutStr("Invalid address");
  237.     break;
  238.  
  239.       case IOERR_UNITBUSY:
  240.     PutStr("Unit is busy");
  241.     break;
  242.  
  243.       case IOERR_SELFTEST:
  244.     PutStr("Hardware failed self-test");
  245.     break;
  246.  
  247.       case S2ERR_NO_ERROR:
  248.     PutStr("No error (should not happen)");
  249.     break;
  250.  
  251.       case S2ERR_NO_RESOURCES:
  252.     PutStr("Resource allocation failure");
  253.     break;
  254.  
  255.       case S2ERR_BAD_ARGUMENT:
  256.     PutStr("Bad argument");
  257.     break;
  258.  
  259.       case S2ERR_BAD_STATE:
  260.     PutStr("Bad state");
  261.     break;
  262.  
  263.       case S2ERR_BAD_ADDRESS:
  264.     PutStr("Bad address");
  265.     break;
  266.  
  267.       case S2ERR_MTU_EXCEEDED:
  268.     PutStr("Maximum transfer length exceeded");
  269.     break;
  270.  
  271.       case S2ERR_NOT_SUPPORTED:
  272.     PutStr("Command not supported");
  273.     break;
  274.  
  275.       case S2ERR_SOFTWARE:
  276.     PutStr("Software error");
  277.     break;
  278.  
  279.       case S2ERR_OUTOFSERVICE:
  280.     PutStr("Driver is offline");
  281.     break;
  282.  
  283.       default:
  284.     Printf("%ld", req->ios2_Req.io_Error);
  285.     break;
  286.     }
  287.  
  288.   if(req->ios2_WireError != S2WERR_GENERIC_ERROR)
  289.     {
  290.       PutStr("\nWireError: ");
  291.  
  292.       switch(req->ios2_WireError)
  293.     {
  294.       case S2WERR_GENERIC_ERROR:
  295.         PutStr("(no specific information)");
  296.         break;
  297.  
  298.       case S2WERR_NOT_CONFIGURED:
  299.         PutStr("Unit is not configured");
  300.         break;
  301.  
  302.       case S2WERR_UNIT_ONLINE:
  303.         PutStr("Unit is currently online");
  304.         break;
  305.  
  306.       case S2WERR_UNIT_OFFLINE:
  307.         PutStr("Unit is currently offline");
  308.         break;
  309.  
  310.       case S2WERR_ALREADY_TRACKED:
  311.         PutStr("Protocol is already being tracked");
  312.         break;
  313.  
  314.       case S2WERR_NOT_TRACKED:
  315.         PutStr("Protocol is not being tracked");
  316.         break;
  317.  
  318.       case S2WERR_BUFF_ERROR:
  319.         PutStr("Buffer management error");
  320.         break;
  321.  
  322.       case S2WERR_SRC_ADDRESS:
  323.         PutStr("Source address error");
  324.         break;
  325.  
  326.       case S2WERR_DST_ADDRESS:
  327.         PutStr("Destination address error");
  328.         break;
  329.  
  330.       case S2WERR_BAD_BROADCAST:
  331.         PutStr("Broadcast error");
  332.         break;
  333.  
  334.       case S2WERR_BAD_MULTICAST:
  335.         PutStr("Multicast error");
  336.         break;
  337.  
  338.       case S2WERR_MULTICAST_FULL:
  339.         PutStr("Multicast address list full");
  340.         break;
  341.  
  342.       case S2WERR_BAD_EVENT:
  343.         PutStr("Unsupported event class");
  344.         break;
  345.  
  346.       case S2WERR_BAD_STATDATA:
  347.         PutStr("StatData failed sanity check");
  348.         break;
  349.  
  350.       case S2WERR_IS_CONFIGURED:
  351.         PutStr("Attempt to configure twice");
  352.         break;
  353.  
  354.       case S2WERR_NULL_POINTER:
  355.         PutStr("Null pointer");
  356.         break;
  357.  
  358.       default:
  359.         Printf("%ld", req->ios2_WireError);
  360.         break;
  361.     }
  362.     }
  363.   PutStr("\n");
  364. }
  365.  
  366.  
  367. void CleanExit(char *msg, int code)
  368. {
  369.   if(msg != NULL)
  370.     {
  371.       Printf("%s: ", ProgName);
  372.       PutStr(msg);
  373.     }
  374.  
  375.   if(code != 0)
  376.     PrintFault(code, ProgName);
  377.  
  378.   if(ProgArgs != NULL)
  379.     FreeArgs(ProgArgs);
  380.  
  381.   if(SanaDev != NULL)
  382.     CloseDevice((struct IORequest *)SanaReq);
  383.  
  384.   if(SanaReq != NULL)
  385.     DeleteIORequest(SanaReq);
  386.  
  387.   if(SanaPort != NULL)
  388.     DeleteMsgPort(SanaPort);
  389.  
  390.   if(PacketBuf != NULL)
  391.     FreeMem(PacketBuf, PacketBufSize);
  392.  
  393.   exit(msg == NULL && code == 0 ? RETURN_OK : RETURN_ERROR);
  394. }
  395.  
  396. void Open_Sana_Device(char *name, int unit, int flags)
  397. {
  398.   static ULONG SanaTags[] = {
  399.     S2_CopyToBuff, (ULONG)MemCopy,
  400.     S2_CopyFromBuff, (ULONG)MemCopy,
  401.     TAG_DONE, 0
  402.   };
  403.  
  404.   if((SanaPort = CreateMsgPort()) == NULL)
  405.     CleanExit("Can't create MsgPort\n", 0);
  406.  
  407.   if((SanaReq = (struct IOSana2Req *)CreateIORequest(SanaPort,
  408.      sizeof(struct IOSana2Req))) == NULL)
  409.     CleanExit("Can't create IORequest\n", 0);
  410.  
  411.   SanaReq->ios2_BufferManagement = SanaTags;
  412.  
  413.   if(OpenDevice(name, unit, (struct IORequest *)SanaReq, flags) != 0)
  414.     {
  415.       Printf("Can't open device %s unit %ld", name, unit);
  416.       Sana2ErrorMsg(SanaReq);
  417.       CleanExit("", 0);
  418.     }
  419.  
  420.   SanaDev = SanaReq->ios2_Req.io_Device;
  421. }
  422.  
  423. void Config(UBYTE *addr)
  424. {
  425. #ifdef DEBUG
  426.   PutStr("Config\n");
  427. #endif
  428.  
  429.   if(addr != NULL)
  430.     memcpy(SanaReq->ios2_SrcAddr, addr, SANA2_MAX_ADDR_BYTES);
  431.   else
  432.     {
  433.       SanaReq->ios2_Req.io_Command = S2_GETSTATIONADDRESS;
  434.       if(DoIO((struct IORequest *)SanaReq) != 0)
  435.     {
  436.       PutStr("GetStationAddress failed");
  437.       Sana2ErrorMsg(SanaReq);
  438.       return;
  439.     }
  440.  
  441.       memcpy(SanaReq->ios2_SrcAddr, SanaReq->ios2_DstAddr,
  442.          SANA2_MAX_ADDR_BYTES);
  443.     }
  444.  
  445.   SanaReq->ios2_Req.io_Command = S2_CONFIGINTERFACE;
  446.   if(DoIO((struct IORequest *)SanaReq) != 0)
  447.     {
  448.       PutStr("ConfigInterface failed");
  449.       Sana2ErrorMsg(SanaReq);
  450.     }
  451. }
  452.  
  453. void OffLine(void)
  454. {
  455. #ifdef DEBUG
  456.   PutStr("OffLine\n");
  457. #endif
  458.  
  459.   SanaReq->ios2_Req.io_Command = S2_OFFLINE;
  460.  
  461.   if(DoIO((struct IORequest *)SanaReq) != 0)
  462.     {
  463.       PutStr("OffLine command failed");
  464.       Sana2ErrorMsg(SanaReq);
  465.     }
  466. }
  467.  
  468. void OnLine(void)
  469. {
  470. #ifdef DEBUG
  471.   PutStr("OnLine\n");
  472. #endif
  473.  
  474.   SanaReq->ios2_Req.io_Command = S2_ONLINE;
  475.  
  476.   if(DoIO((struct IORequest *)SanaReq) != 0)
  477.     {
  478.       PutStr("OnLine command failed");
  479.       Sana2ErrorMsg(SanaReq);
  480.     }
  481. }
  482.  
  483. void Status(void)
  484. {
  485.   static struct Sana2DeviceQuery ALIGNED DevQuery;
  486.   static struct Sana2DeviceStats ALIGNED DevStat;
  487.   static struct SpecialStatData ALIGNED SpecialStats;
  488.   int addr_bytes;
  489.   int i;
  490.  
  491.   SanaReq->ios2_Req.io_Command = S2_DEVICEQUERY;
  492.   SanaReq->ios2_StatData = &DevQuery;
  493.   DevQuery.SizeAvailable = sizeof(struct Sana2DeviceQuery);
  494.   if(DoIO((struct IORequest *)SanaReq) != 0)
  495.     {
  496.       PutStr("DeviceQuery failed");
  497.       Sana2ErrorMsg(SanaReq);
  498.       return;
  499.     }
  500.  
  501. /*
  502.   Printf("SizeAvailable: %ld, SizeSupplied: %ld\n",
  503.     DevQuery.SizeAvailable, DevQuery.SizeSupplied);
  504.  */
  505.  
  506.   Printf("QueryFormat: %ld, DeviceLevel: %ld\n",
  507.      DevQuery.DevQueryFormat, DevQuery.DeviceLevel);
  508.  
  509.   Printf("Address field size: %ld bits, Maximum transfer unit: %ld bytes\n",
  510.      DevQuery.AddrFieldSize, DevQuery.MTU);
  511.   Printf("Speed: %ld bps, HardwareType: ", DevQuery.BPS);
  512.  
  513.   switch(DevQuery.HardwareType)
  514.     {
  515.       case S2WireType_Ethernet:
  516.     PutStr("Ethernet");
  517.     break;
  518.  
  519.       case S2WireType_IEEE802:
  520.     PutStr("IEEE802.3");
  521.     break;
  522.  
  523.       case S2WireType_Arcnet:
  524.     PutStr("ArcNet");
  525.     break;
  526.  
  527.       case S2WireType_LocalTalk:
  528.     PutStr("LocalTalk");
  529.     break;
  530.  
  531.       case S2WireType_AmokNet:
  532.     PutStr("AmokNet");
  533.     break;
  534.  
  535.       case S2WireType_PPP:
  536.     PutStr("PPP");
  537.     break;
  538.  
  539.       case S2WireType_SLIP:
  540.     PutStr("SLIP");
  541.     break;
  542.  
  543.       case S2WireType_CSLIP:
  544.     PutStr("Compressed SLIP");
  545.     break;
  546.  
  547.       default:
  548.     Printf("%ld", DevQuery.HardwareType);
  549.     break;
  550.     }
  551.  
  552.   PutStr("\n");
  553.  
  554.   SanaReq->ios2_Req.io_Command = S2_GETSTATIONADDRESS;
  555.   if(DoIO((struct IORequest *)SanaReq) != 0)
  556.     {
  557.       Printf("GetStationAddress failed");
  558.       Sana2ErrorMsg(SanaReq);
  559.       return;
  560.     }
  561.  
  562.   if(DevQuery.AddrFieldSize > SANA2_MAX_ADDR_BITS)
  563.     {
  564.       PutStr("Address field size too large!\n");
  565.       return;
  566.     }
  567.  
  568.   if(DevQuery.AddrFieldSize & 7)
  569.     PutStr("Warning: Address size not divisible by 8\n");
  570.  
  571.   addr_bytes = (DevQuery.AddrFieldSize+7)/8;
  572.  
  573.   PutStr("Current addr: ");
  574.   ShowAddress(SanaReq->ios2_SrcAddr, addr_bytes);
  575.   PutStr(", Default addr: ");
  576.   ShowAddress(SanaReq->ios2_DstAddr, addr_bytes);
  577.   PutStr("\n");
  578.  
  579.   SanaReq->ios2_Req.io_Command = S2_GETGLOBALSTATS;
  580.   SanaReq->ios2_StatData = &DevStat;
  581.   if(DoIO((struct IORequest *)SanaReq) != 0)
  582.     {
  583.       Printf("GetGlobalStats failed");
  584.       Sana2ErrorMsg(SanaReq);
  585.     }
  586.   else /* GetGlobalStats successfull */
  587.     {
  588.       /*
  589.        * This requires at least revision 1.11 of sana2.h include file
  590.        * (some structure offsets are wrong in older versions)
  591.        */
  592.       Printf("Packets received: %ld, Packets sent: %ld\n",
  593.          DevStat.PacketsReceived, DevStat.PacketsSent);
  594.       Printf("Bad Data: %ld, Overruns: %ld\n",
  595.          DevStat.BadData, DevStat.Overruns);
  596.  
  597.       Printf("Unknown packets received: %ld, Reconfigurations: %ld\n",
  598.          DevStat.UnknownTypesReceived, DevStat.Reconfigurations);
  599.  
  600.       PutStr("Last start: ");
  601.       if(DevStat.LastStart.tv_secs == 0)
  602.     PutStr("--\n");
  603.       else
  604.     {
  605.       static struct DateTime dt;
  606.       static char str_day[LEN_DATSTRING];
  607.       static char str_date[LEN_DATSTRING];
  608.       static char str_time[LEN_DATSTRING];
  609.  
  610.       dt.dat_Stamp.ds_Days = DevStat.LastStart.tv_secs / 86400;
  611.       dt.dat_Stamp.ds_Minute = (DevStat.LastStart.tv_secs  % 86400)
  612.         / 60;
  613.       dt.dat_Stamp.ds_Tick = (DevStat.LastStart.tv_secs % 60) * 50;
  614.       dt.dat_Format = FORMAT_DOS;
  615.       dt.dat_Flags = 0;
  616.       dt.dat_StrDay = str_day;
  617.       dt.dat_StrDate = str_date;
  618.       dt.dat_StrTime = str_time;
  619.  
  620.       DateToStr(&dt);
  621.  
  622.       Printf("%s %s %s\n", str_day, str_date, str_time);
  623.     }
  624.      }
  625.  
  626.   SpecialStats.hdr.RecordCountMax = MAX_SPECIALSTATS;
  627.   SanaReq->ios2_Req.io_Command = S2_GETSPECIALSTATS;
  628.   SanaReq->ios2_StatData = &SpecialStats;
  629.   if(DoIO((struct IORequest *)SanaReq) != 0)
  630.     {
  631.       Printf("GetSpecialStats failed");
  632.       Sana2ErrorMsg(SanaReq);
  633.     }
  634.   else /* GetSpecialStats successfull */
  635.     {
  636.       if(SpecialStats.hdr.RecordCountSupplied == 0)
  637.     PutStr("No special stat data\n");
  638.       else
  639.     {
  640.       PutStr("Special stats:\n");
  641.       for(i = 0; i < SpecialStats.hdr.RecordCountSupplied; i++)
  642.         {
  643.           Printf("(%ld/%ld) %s: %ld\n",
  644.              SpecialStats.stat[i].Type >> 16,
  645.              SpecialStats.stat[i].Type & 0xffff,
  646.              SpecialStats.stat[i].String,
  647.              SpecialStats.stat[i].Count);
  648.         }
  649.     }
  650.     }
  651. }
  652.  
  653. /*
  654.  * Packet dump -- this may miss a lot of packets,
  655.  * but it is useful in debugging anyway...
  656.  *
  657.  */
  658. void Dump(void)
  659. {
  660.   static struct Sana2DeviceQuery ALIGNED DevQuery;
  661.   int addr_bytes;
  662.  
  663.   SanaReq->ios2_Req.io_Command = S2_DEVICEQUERY;
  664.   SanaReq->ios2_StatData = &DevQuery;
  665.   DevQuery.SizeAvailable = sizeof(struct Sana2DeviceQuery);
  666.   if(DoIO((struct IORequest *)SanaReq) != 0)
  667.     {
  668.       PutStr("DeviceQuery failed");
  669.       Sana2ErrorMsg(SanaReq);
  670.       return;
  671.     }
  672.  
  673. /*
  674.  * Note that packet buffer needs to be big enough
  675.  * for the packet data and header (and possible CRC)
  676.  * fields, as we use the SANA2IOF_RAW-flag
  677.  *
  678.  * There is no way to ask the sizes of these fields
  679.  * from the sana2 device, so we just assume that they
  680.  * cannot be bigger than 256 bytes
  681.  */
  682.   PacketBufSize = DevQuery.MTU + 256;
  683.  
  684.   if(DevQuery.AddrFieldSize & 7)
  685.     PutStr("Warning: Address size not divisible by 8\n");
  686.  
  687.   addr_bytes = (DevQuery.AddrFieldSize+7)/8;
  688.  
  689.   if((PacketBuf = AllocMem(PacketBufSize, MEMF_CLEAR)) == NULL)
  690.     CleanExit("Out of memory\n", 0);
  691.  
  692.   PutStr("Waiting for packets...\n");
  693.  
  694.   for(;;)
  695.     {
  696.       SanaReq->ios2_Req.io_Command = S2_READORPHAN;
  697.       SanaReq->ios2_Req.io_Flags = SANA2IOF_RAW;
  698.       SanaReq->ios2_DataLength = PacketBufSize; /* not really used */
  699.       SanaReq->ios2_Data = PacketBuf;
  700.       BeginIO((struct IORequest *)SanaReq);
  701.       if(Wait(SIGBREAKF_CTRL_C | (1 << SanaPort->mp_SigBit))
  702.      & SIGBREAKF_CTRL_C)
  703.     {
  704.       AbortIO((struct IORequest *)SanaReq);
  705.       WaitIO((struct IORequest *)SanaReq);
  706.       CleanExit("***Break\n", 0);
  707.     }
  708.       if(WaitIO((struct IORequest *)SanaReq) != 0)
  709.     {
  710.       PutStr("ReadOrphan failed");
  711.       Sana2ErrorMsg(SanaReq);
  712.       return;
  713.     }
  714.       else
  715.     {
  716.       PutStr("Packet from ");
  717.       ShowAddress(SanaReq->ios2_SrcAddr, addr_bytes);
  718.       Printf(", length %ld\n", SanaReq->ios2_DataLength);
  719.       HexDump(PacketBuf, SanaReq->ios2_DataLength);
  720.     }
  721.     }
  722. }
  723.  
  724. /*
  725.  * Receive specific type packets
  726.  *
  727.  */
  728. void Receive(int type)
  729. {
  730.   static struct Sana2DeviceQuery ALIGNED DevQuery;
  731.   int addr_bytes;
  732.  
  733.   SanaReq->ios2_Req.io_Command = S2_DEVICEQUERY;
  734.   SanaReq->ios2_StatData = &DevQuery;
  735.   DevQuery.SizeAvailable = sizeof(struct Sana2DeviceQuery);
  736.   if(DoIO((struct IORequest *)SanaReq) != 0)
  737.     {
  738.       PutStr("DeviceQuery failed");
  739.       Sana2ErrorMsg(SanaReq);
  740.       return;
  741.     }
  742.  
  743. /* see note in the Dump-function */
  744.   PacketBufSize = DevQuery.MTU + 256;
  745.  
  746.   if(DevQuery.AddrFieldSize & 7)
  747.     PutStr("Warning: Address size not divisible by 8\n");
  748.  
  749.   addr_bytes = (DevQuery.AddrFieldSize+7)/8;
  750.  
  751.   if((PacketBuf = AllocMem(PacketBufSize, MEMF_CLEAR)) == NULL)
  752.     CleanExit("Out of memory\n", 0);
  753.  
  754.   Printf("Waiting for packets (type %ld (0x%lx)...\n", type, type);
  755.  
  756.   for(;;)
  757.     {
  758.       SanaReq->ios2_Req.io_Command = CMD_READ;
  759.       SanaReq->ios2_Req.io_Flags = SANA2IOF_RAW;
  760.       SanaReq->ios2_DataLength = PacketBufSize; /* not really used */
  761.       SanaReq->ios2_PacketType = type;
  762.       SanaReq->ios2_Data = PacketBuf;
  763.       BeginIO((struct IORequest *)SanaReq);
  764.       if(Wait(SIGBREAKF_CTRL_C | (1 << SanaPort->mp_SigBit))
  765.      & SIGBREAKF_CTRL_C)
  766.     {
  767.       AbortIO((struct IORequest *)SanaReq);
  768.       WaitIO((struct IORequest *)SanaReq);
  769.       CleanExit("***Break\n", 0);
  770.     }
  771.       if(WaitIO((struct IORequest *)SanaReq) != 0)
  772.     {
  773.       PutStr("CMD_READ failed");
  774.       Sana2ErrorMsg(SanaReq);
  775.       return;
  776.     }
  777.       else
  778.     {
  779.       PutStr("Packet from ");
  780.           ShowAddress(SanaReq->ios2_SrcAddr, addr_bytes);
  781.       Printf(", length %ld\n", SanaReq->ios2_DataLength);
  782.       HexDump(PacketBuf, SanaReq->ios2_DataLength);
  783.     }
  784.     }
  785. }
  786.  
  787. /*
  788.  * Send packet (handles broadcasts and multicasts)
  789.  *
  790.  */
  791. void Send(char *addr_str, int type, int len, char *datastr, int flags)
  792. {
  793.   if(datastr == NULL)
  794.     datastr = "SANAutil test packet -- ";
  795.  
  796.   if(flags & SANA2IOF_BCAST)
  797.     SanaReq->ios2_Req.io_Command =S2_BROADCAST;
  798.   else
  799.     {
  800.       if(!ParseAddr(addr_str, SanaReq->ios2_DstAddr))
  801.     CleanExit("Bad address argument\n", 0);
  802.  
  803.       if(flags & SANA2IOF_MCAST)
  804.     SanaReq->ios2_Req.io_Command =S2_MULTICAST;
  805.       else
  806.     SanaReq->ios2_Req.io_Command = CMD_WRITE;
  807.     }
  808.  
  809.   PacketBufSize = len;
  810.   if((PacketBuf = AllocMem(PacketBufSize, MEMF_CLEAR)) == NULL)
  811.     CleanExit("Out of memory\n", 0);
  812.  
  813.   StringFill(PacketBuf, len, datastr);
  814.  
  815. #ifdef DEBUG
  816.   Printf("Send: Length: %ld, packet type $%lx\n", len, type);
  817. #endif
  818.  
  819.   SanaReq->ios2_Data = PacketBuf;
  820.   SanaReq->ios2_DataLength = len;
  821.   SanaReq->ios2_PacketType = type;
  822.   SanaReq->ios2_Req.io_Flags = 0;
  823.   BeginIO((struct IORequest *)SanaReq);
  824.   if(WaitIO((struct IORequest *)SanaReq) != 0)
  825.     {
  826.       PutStr("Packet send failed");
  827.       Sana2ErrorMsg(SanaReq);
  828.     }
  829. }
  830.  
  831. /*
  832.  * Add a multicast address
  833.  *
  834.  */
  835. void AddMultiCast(char *addr_str)
  836. {
  837.   if(!ParseAddr(addr_str, SanaReq->ios2_SrcAddr))
  838.     CleanExit("Bad address argument\n", 0);
  839.  
  840.   SanaReq->ios2_Req.io_Command = S2_ADDMULTICASTADDRESS;
  841.   if(DoIO((struct IORequest *)SanaReq) != 0)
  842.      {
  843.     PutStr("AddMultiCast failed");
  844.     Sana2ErrorMsg(SanaReq);
  845.      }
  846. }
  847.  
  848. /*
  849.  * Remove a multicast address
  850.  *
  851.  */
  852. void DelMultiCast(char *addr_str)
  853. {
  854.   if(!ParseAddr(addr_str, SanaReq->ios2_SrcAddr))
  855.     CleanExit("Bad address argument\n", 0);
  856.  
  857.   SanaReq->ios2_Req.io_Command = S2_DELMULTICASTADDRESS;
  858.   if(DoIO((struct IORequest *)SanaReq) != 0)
  859.      {
  860.     PutStr("DelMultiCast failed");
  861.     Sana2ErrorMsg(SanaReq);
  862.      }
  863. }
  864.  
  865. /*
  866.  * Add type tracking
  867.  *
  868.  */
  869. void TrackType(LONG type)
  870. {
  871.   SanaReq->ios2_Req.io_Command = S2_TRACKTYPE;
  872.   SanaReq->ios2_PacketType = type;
  873.   if(DoIO((struct IORequest *)SanaReq) != 0)
  874.     {
  875.       PutStr("TrackType failed");
  876.       Sana2ErrorMsg(SanaReq);
  877.     }
  878. }
  879.  
  880. /*
  881.  * Remove type tracking
  882.  *
  883.  */
  884. void UnTrackType(LONG type)
  885. {
  886.   SanaReq->ios2_Req.io_Command = S2_UNTRACKTYPE;
  887.   SanaReq->ios2_PacketType = type;
  888.   if(DoIO((struct IORequest *)SanaReq) != 0)
  889.     {
  890.       PutStr("UnTrackType failed");
  891.       Sana2ErrorMsg(SanaReq);
  892.     }
  893. }
  894.  
  895. /*
  896.  * Statistics for a tracked packet type
  897.  *
  898.  */
  899. void TypeStats(LONG type)
  900. {
  901.   static struct Sana2PacketTypeStats ALIGNED typestat;
  902.  
  903.   SanaReq->ios2_Req.io_Command = S2_GETTYPESTATS;
  904.   SanaReq->ios2_StatData = &typestat;
  905.   SanaReq->ios2_PacketType = type;
  906.   if(DoIO((struct IORequest *)SanaReq) != 0)
  907.     {
  908.       PutStr("GetTypeStats failed");
  909.       Sana2ErrorMsg(SanaReq);
  910.       return;
  911.     }
  912.  
  913.   Printf("Type %ld stats:\n", type);
  914.   Printf("Packets sent: %ld, Packets received: %ld\n",
  915.      typestat.PacketsSent, typestat.PacketsReceived);
  916.   Printf("Bytes sent: %ld, Bytes received: %ld\n",
  917.      typestat.BytesSent, typestat.BytesReceived);
  918.   Printf("Packets dropped: %ld\n", typestat.PacketsDropped);
  919. }
  920.  
  921. /*
  922.  * Display an usage/help message
  923.  *
  924.  */
  925. void Usage(void)
  926. {
  927.   PutStr(
  928.    "SanaUtil " VERSION "." REVISION " © 1992-1995 by Timo Rossi <trossi@jyu.fi>\n"
  929.    "  -d <device_name> or DEVICE <device_name>\t--  select device\n"
  930.    "  -u <unit_number> or UNIT <unit_number>\t--  select unit\n"
  931.    "\t(Prepends 'networks/' to the name if not a full path,\n"
  932.    "\tuses env. vars SANA2.Device and SANA2.Unit if these options\n"
  933.    "\tare not used. Default is a2065.device, unit 0)\n"
  934.    "  -e or EXCLUSIVE\t\t-- exclusive access mode\n"
  935.    "  -p or PROMISCUOUS\t\t-- promiscuous mode\n"
  936.    "\t(doesn't check destination addresses)\n"
  937.    "  SEND <destination_address>\t-- send a packet\n"
  938.    "  MULTICAST <multicast_address>\t-- send a multicast packet\n"
  939.    "  BROADCAST\t\t\t-- send a broadcast packet\n"
  940.    "\tTYPE <packet_type>\t-- type of packet (decimal, default 5000)\n"
  941.    "\tLENGTH <length>\t\t-- length of packet to send (default 100)\n"
  942.    "\tDATA <string>\t\t-- ASCII data string to send\n"
  943.    "  DUMP\t\t\t-- display received packets (no multiple buffering)\n"
  944.    "  RECEIVE <type>\t-- receive/display specific type packets\n"
  945.    "  STATUS\t\t-- display device information and statistics\n"
  946.    "  CONFIG\t\t-- configure the device (can be done only once)\n"
  947.    "  ONLINE\t\t-- places the device online\n"
  948.    "  OFFLINE\t\t-- places the device offline\n"
  949.    "  ADDMULTICAST <addr>\t-- add a multicast receive address\n"
  950.    "  DELMULTICAST <addr>\t-- remove a multicast receive address\n"
  951.    "  TRACKTYPE <type>\t-- track a new packet type\n"
  952.    "  UNTRACKTYPE <type>\t-- remove packet type tracking\n"
  953.    "  TYPESTAT <type>\t-- display statistics about a tracked packet type\n"
  954.   );
  955. }
  956.  
  957. /*
  958.  * Main program
  959.  *
  960.  */
  961. #ifdef __SASC
  962. void __stdargs _main(char *cmdline)
  963. #else
  964. main()
  965. #endif
  966. {
  967.   static ULONG ArgArray[NUM_ARGS];
  968.   static char dev_name_string[256];
  969.   static char buff[256];
  970.   static LONG dev_unit_num;
  971.   static int dev_flags, type, len;
  972.   char *dev_name;
  973.   char *send_data = NULL;
  974.   UBYTE addr[SANA2_MAX_ADDR_BYTES];
  975.   int k;
  976.  
  977.   if(DOSBase->dl_lib.lib_Version < 37)
  978.      {
  979. #define OS_VERSION_MSG "This program requires Amiga OS 2.04 or later (V37)\n"
  980.     BPTR out;
  981.     if(out = Output())
  982.       Write(out, OS_VERSION_MSG, sizeof(OS_VERSION_MSG)-1);
  983.     exit(RETURN_FAIL);
  984.      }
  985.  
  986.   memset(ArgArray, 0, sizeof(ArgArray));
  987.   if((ProgArgs = ReadArgs(Prog_Template, ArgArray, NULL)) == NULL)
  988.     CleanExit(NULL, IoErr());
  989.  
  990.   if(ArgArray[UNIT_ARG] != 0)
  991.     dev_unit_num = *((LONG *)ArgArray[UNIT_ARG]);
  992.   else if(GetVar("SANA2.Unit", buff, 255, 0) > 0)
  993.     StrToLong(buff, &dev_unit_num);
  994.   else
  995.     dev_unit_num = DEFAULT_UNIT_NUMBER;
  996.  
  997.   if(ArgArray[DEVICE_ARG] != 0)
  998.     dev_name = (char *)ArgArray[DEVICE_ARG];
  999.   else if(GetVar("SANA2.Device", buff, 255, 0) > 0)
  1000.     dev_name = buff;
  1001.   else
  1002.     dev_name = DEFAULT_DEVICE_NAME;
  1003.  
  1004.   if(!strchr(dev_name, ':') && !strchr(dev_name, '/'))
  1005.     strcpy(dev_name_string, "networks/");
  1006.   else
  1007.     dev_name_string[0] = '\0';
  1008.  
  1009.   strcat(dev_name_string, dev_name);
  1010.  
  1011.   k =    (ArgArray[ONLINE_ARG] != 0) + (ArgArray[OFFLINE_ARG] != 0) +
  1012.     (ArgArray[CONFIG_ARG] != 0) + (ArgArray[STATUS_ARG] != 0) +
  1013.     (ArgArray[RECEIVE_ARG] != 0) +
  1014.     (ArgArray[DUMP_ARG] != 0) + (ArgArray[SEND_ARG] != 0) +
  1015.     (ArgArray[BROADCAST_ARG] != 0) + (ArgArray[MULTICAST_ARG] != 0) +
  1016.     (ArgArray[ADDMULTICAST_ARG] != 0) + (ArgArray[DELMULTICAST_ARG] != 0) +
  1017.     (ArgArray[TRACKTYPE_ARG] != 0) + (ArgArray[UNTRACKTYPE_ARG] != 0) +
  1018.     (ArgArray[TYPESTAT_ARG] != 0);
  1019.  
  1020.   if(k == 0)
  1021.     {
  1022.       Usage();
  1023.       CleanExit(NULL, 0);
  1024.     }
  1025.  
  1026.   if(k != 1 ||
  1027.      (ArgArray[CONFIG_ARG] == 0 && ArgArray[ADDR_ARG]) ||
  1028.      (ArgArray[SEND_ARG] == 0 && ArgArray[BROADCAST_ARG] == 0 &&
  1029.       ArgArray[MULTICAST_ARG] == 0 &&
  1030.       (ArgArray[LENGTH_ARG] != 0 || ArgArray[TYPE_ARG] != 0)))
  1031.     CleanExit("Bad arguments\n", 0);
  1032.  
  1033.   if(ArgArray[ADDR_ARG] && !ParseAddr((char *)ArgArray[ADDR_ARG], addr))
  1034.     CleanExit("Bad address argument\n", 0);
  1035.  
  1036.   dev_flags = 0;
  1037.   if(ArgArray[EXCL_ARG])
  1038.     dev_flags |= SANA2OPF_MINE;
  1039.   if(ArgArray[PROM_ARG])
  1040.     dev_flags |= SANA2OPF_PROM;
  1041.  
  1042.   if(ArgArray[SEND_ARG] || ArgArray[BROADCAST_ARG] || ArgArray[MULTICAST_ARG])
  1043.     {
  1044.       if(ArgArray[TYPE_ARG] == 0)
  1045.     type = DEFAULT_PACKET_TYPE;
  1046.       else
  1047.     type = *((LONG *)ArgArray[TYPE_ARG]);
  1048.  
  1049.       if(ArgArray[LENGTH_ARG] == 0)
  1050.     len = DEFAULT_PACKET_LEN;
  1051.       else
  1052.     len = *((LONG *)ArgArray[LENGTH_ARG]);
  1053.  
  1054.       if(ArgArray[DATA_ARG] != 0)
  1055.     send_data = (char *)ArgArray[DATA_ARG];
  1056.     }
  1057.  
  1058. #ifdef DEBUG
  1059.   Printf("Device: %s, Unit %ld, Flags %ld\n",
  1060.      dev_name_string, dev_unit_num, dev_flags);
  1061. #endif
  1062.  
  1063.   Open_Sana_Device(dev_name_string, dev_unit_num, dev_flags);
  1064.  
  1065. #ifdef DEBUG
  1066.   Printf("Port = $%lx, Req = $%lx, Dev = $%lx\n", SanaPort, SanaReq, SanaDev);
  1067. #endif
  1068.  
  1069.   if(ArgArray[TRACKTYPE_ARG])
  1070.     TrackType(*((LONG *)ArgArray[TRACKTYPE_ARG]));
  1071.   else if(ArgArray[UNTRACKTYPE_ARG])
  1072.     UnTrackType(*((LONG *)ArgArray[UNTRACKTYPE_ARG]));
  1073.   else if(ArgArray[TYPESTAT_ARG])
  1074.     TypeStats(*((LONG *)ArgArray[TYPESTAT_ARG]));
  1075.   else if(ArgArray[ADDMULTICAST_ARG])
  1076.     AddMultiCast((char *)ArgArray[ADDMULTICAST_ARG]);
  1077.   else if(ArgArray[DELMULTICAST_ARG])
  1078.     DelMultiCast((char *)ArgArray[DELMULTICAST_ARG]);
  1079.   else if(ArgArray[DUMP_ARG])
  1080.     Dump();
  1081.   else if(ArgArray[RECEIVE_ARG])
  1082.     Receive(*((LONG *)ArgArray[RECEIVE_ARG]));
  1083.   else if(ArgArray[SEND_ARG])
  1084.     Send((char *)ArgArray[SEND_ARG], type, len, send_data, 0);
  1085.   else if(ArgArray[BROADCAST_ARG])
  1086.     Send(NULL, type, len, send_data, SANA2IOF_BCAST);
  1087.   else if(ArgArray[MULTICAST_ARG])
  1088.     Send((char *)ArgArray[MULTICAST_ARG], type, len, send_data, SANA2IOF_MCAST);
  1089.   else if(ArgArray[STATUS_ARG])
  1090.     {
  1091.       Printf("Device '%s' (version %ld.%ld), unit %ld\n",
  1092.          dev_name_string, SanaDev->dd_Library.lib_Version,
  1093.          SanaDev->dd_Library.lib_Revision, dev_unit_num);
  1094.       Status();
  1095.     }
  1096.   else if(ArgArray[CONFIG_ARG])
  1097.     Config(ArgArray[ADDR_ARG] ? addr : NULL);
  1098.   else if(ArgArray[ONLINE_ARG])
  1099.     OnLine();
  1100.   else if(ArgArray[OFFLINE_ARG])
  1101.     OffLine();
  1102.  
  1103.   CleanExit(NULL, 0);
  1104. }
  1105.